package flow

import (
	"wowCoupon.com/cache"
)

var (
	BusinessBf *BloomFilter
	CouponBf   *BloomFilter
)

func Setup() {
	// init BusinessBf
	BusinessBf = NewBloomFilter("BusinessBf", 0.000001, 10000000)

	if BusinessBf == nil {
		panic("bloomFilter 'BusinessBf' is nil")
	}

	/*
		if ok := BusinessBf.Reserve(); !ok {
			panic("bloomFilter 'BusinessBf' set up failed")
		}
	*/

	// init CouponBf
	CouponBf = NewBloomFilter("CouponBf", 0.000001, 10000000)

	if CouponBf == nil {
		panic("bloomFilter 'CouponBf' is nil")
	}

	/*
		if ok := CouponBf.Reserve(); !ok {
			panic("bloomFilter 'CouponBf' set up failed")
		}
	*/
}

/*BloomFilter for flow control*/
type BloomFilter struct {
	Name     string
	ErrRate  float64
	Capacity int64
}

func NewBloomFilter(name string, errRate float64, capacity int64) *BloomFilter {
	b := &BloomFilter{
		Name:     name,
		ErrRate:  errRate,
		Capacity: capacity,
	}

	if exist, _ := cache.Rdb.Exists(b.Name); !exist {
		b.Reserve()
	}

	return b
}

func (b *BloomFilter) Reserve() bool {
	if ok, _ := cache.Rdb.BfReserve(b.Name, b.ErrRate, b.Capacity); !ok {
		return false
	}

	return true
}

func (b *BloomFilter) BfAdd(item string) bool {
	if ok, _ := cache.Rdb.BfAdd(b.Name, item); !ok {
		return false
	}

	return true
}

// Determines whether an item may exist in the Bloom Filter or not.
func (b *BloomFilter) BfExists(item string) bool {
	if ok, _ := cache.Rdb.BfExists(b.Name, item); !ok {
		return false
	}

	return true
}

//Allow item or not
func (b *BloomFilter) Allow(item string) bool {
	alreadyDoneBefore, _ := b.seen(item)

	if alreadyDoneBefore {
		//false positives are possible
		return false
	}

	return true
}

//seen item before or not
func (b *BloomFilter) seen(item string) (bool, error) {
	ok, err := cache.Rdb.BfAdd(b.Name, item)
	if err != nil {
		return false, err
	}

	if ok {
		return false, nil
	}

	//false positives are possible
	return true, nil
}
